/*
 * TestColeccionFlotas.cpp
 *
 *  Created on: 15/02/2010
 *      Author: San Martín, Matías I.
 */

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdio>
#include <errno.h>


#include "../../Aplicacion/Modelo/Common/Flota.h"
#include "../../Aplicacion/Modelo/EnPlaneta/ColeccionFlotas.h"
#include "../../Framework/Excepciones/BaseExcepcion.h"

using namespace std;

using namespace aplicacion;
using namespace aplicacion::planeta;

static Posicion partida(50,50);
static Posicion partida2(30,150);
static Posicion destino(500,50);
static const T_TIEMPO tIni = 5;

static int d1 = 1;
static int d2 = 15;

static Flota* f1;
static Flota* f2;

static void imprimirFlota(const Flota& flota)
{
	t_constPtrNaves* naves = flota.getNavesPorTiempoHastaCantidad(flota.getCantidadNaves());

	t_constPtrNaves::iterator fin = naves->end();
	for (t_constPtrNaves::iterator i = naves->begin(); i != fin; i++)
	{
		cout << *(*i) << " Tiempo arribo " << (*i)->getTiempoArribo(flota.getDestino()) << "\n";
	}

	delete naves;

}

static IdJugador getJugador(int d)
{
	IdJuego idJuego(1000);
	IdJugador id(50 + d,idJuego);
	return id;
}

/** d se le suma al id de jugador y a la semilla */
static Flota* crearFlota(int d, Posicion part)
{
	IdFlota id(1);
	id.setIdJugador(getJugador(d));

	return new Flota(id, 100 /*cant naves*/, 1 + d /*semilla*/,
				50 /*escala distr*/,
				part, destino,
				tIni /*tiempo*/);
}

/**
 * Este test esta acoplado a los valores de la creacion
 */
static void verificarCantidadArribaran(const ColeccionFlotas& cf)
{
	const size_t cantEsperada = 111;

	size_t cantDicho = cf.getCantidadArribaran(46 + tIni);
	if (cantDicho != cantEsperada)
	{
		cerr << "CANTARR: cantidad arribaran obtenida incorrecta: se esperaban "
						<< cantEsperada << " y se obtuvieron " << cantDicho << "\n";
	}else{
		cout << "Cantidad arribaran OK\n";
	}

}

static void verificarCantidadArribaranInf(const ColeccionFlotas& cf)
{
	const size_t cantEsperada = 200; //todas las flotas

	size_t cantDicho = cf.getCantidadArribaran(TIEMPO_MAX);
	if (cantDicho != cantEsperada)
	{
		cerr << "CANTARRINF: cantidad arribaran obtenida incorrecta: se esperaban "
						<< cantEsperada << " y se obtuvieron " << cantDicho << "\n";
	}else{
		cout << "Cantidad arribaran Inf OK\n";
	}

}

/**
 * Este test esta acoplado a los valores de la creacion
 */
static void verificarTiempoArribaran(const ColeccionFlotas& cf)
{
	const T_TIEMPO tEsperado = 45;

	T_TIEMPO tDicho = cf.getTiempoArribaran(73);
	if (tDicho != tEsperado)
	{
		cerr << "TARR: tiempo arribaran obtenido incorrecto: se esperaba "
						<< tEsperado << " y se obtuvo " << tDicho << "\n";
	}else{
		cout << "Tiempo arribaran OK\n";
	}

}

/**
 * Este test esta acoplado a los valores de la creacion
 */
static void verificarTiempoArribaranSuc(ColeccionFlotas& cf)
{
	const T_TIEMPO tEsperado1 = 42;
	const T_TIEMPO tEsperado2 = 1;
	const T_TIEMPO tEsperado3 = 4;

	T_TIEMPO ttotal = tIni;
	T_TIEMPO tDicho = cf.getTiempoArribaran(10);
	if (tDicho != tEsperado1)
	{
		cerr << "TARRS: tiempo arribaran obtenido incorrecto: se esperaba "
						<< tEsperado1 << " y se obtuvo " << tDicho << "\n";
		return;
	}

	ttotal += tDicho;
	cf.setTiempo(ttotal);

	tDicho = cf.getTiempoArribaran(10);
	if (tDicho != tEsperado2)
	{
		cerr << "TARRS: tiempo arribaran obtenido incorrecto: se esperaba "
				<< tEsperado2 << " y se obtuvo " << tDicho << "\n";
		return;
	}

	ttotal += tDicho;
	cf.setTiempo(ttotal);

	tDicho = cf.getTiempoArribaran(100);
	if (tDicho != tEsperado3)
	{
		cerr << "TARRS: tiempo arribaran obtenido incorrecto: se esperaba "
				<< tEsperado3 << " y se obtuvo " << tDicho << "\n";
		return;
	}

	cout << "Tiempo arribaran OK\n";


}

static void verificarQuedo (ColeccionFlotas& cf)
{
	t_parIdJugadorCantidad queda;
	queda.first = getJugador(d2);
	queda.second = 0;
	queda = cf.getQuedoUltimo(46 + tIni,queda);

	cout << "Cantidad: " << queda.second << endl;

	if (queda.first != getJugador(d1))
	{
		cerr << "QUEDO: ultimo jugador arribo obtenido incorrecto: se esperaba "
						<< getJugador(d1) << " y se obtuvo " << queda.first << "\n";
	}else{
		cout << "Quedo OK\n";
	}

}

static void verificarArribadas(ColeccionFlotas& cf)
{
	const size_t esperabaArriben = 157;
	size_t carribaron = cf.setTiempo(48 + tIni);

	if (carribaron != esperabaArriben)
	{
		cerr << "ARRIBADAS: cantidad de naves arribadas obtenida incorrecta: se esperaba "
								<< esperabaArriben << " y se obtuvo " << carribaron << "\n";
		return;
	}

	t_idFlotasCantidadCollection* arribaron =
			cf.getCantidadNavesFlotasArribaron();

	t_idFlotasCantidadCollection::iterator fin = arribaron->end();
	for (t_idFlotasCantidadCollection::iterator i = arribaron->begin();
			i != fin;
			i++)
	{
		cout << "Arribada: " << i->first << " con " << i->second << endl;
		if (i->first == f1->getId() )
		{
			if (i->second != 0)
			{
				cerr << "ARRIBADAS: cantidad de naves en flota1 obtenida incorrecta: se esperaba "
												<< 0 << " y se obtuvo " << i->second << "\n";
				return;
			}
		}else{
			if (i->second != 43)
			{
				cerr << "ARRIBADAS: cantidad de naves en flota2 obtenida incorrecta: se esperaba "
						<< 43 << " y se obtuvo " << i->second << "\n";
				return;
			}
		}

	}

	cout << "Quedo OK\n";


}

static void verificarArribosSucesivos()
{
	const size_t cantPasos = 6;
	const T_TIEMPO paso[] = {17,1,2,2,3,5};
	T_TIEMPO tiempo = 0;

	IdFlota id(1);
	IdJuego juego(10);
	IdJugador jugador(100,juego);
	id.setIdJugador(jugador);

	Posicion dest(20,25);
	Posicion origen(100,200);
	Flota *flotaNueva = new Flota(id	,
					100,
					9,
					150,
					origen, dest,
					tiempo	);

	imprimirFlota(*flotaNueva);
	ColeccionFlotas cf;
	cf.add(flotaNueva);

	IdJugador otro(11,juego);
	t_parIdJugadorCantidad queda;
	queda.first = otro;
	queda.second = 30;

	for (size_t i = 0; i < cantPasos;i++)
	{
		tiempo += paso[i];
		cout << "Esta antes de arribar: " << queda.first << "(" << queda.second << ")" << endl;
		queda = cf.getQuedoUltimo(tiempo,queda);
		cout << "Esta despues de arribar: " << queda.first << "(" << queda.second << ")" << endl;


		t_idFlotasCantidadCollection* arribaron =
				cf.getCantidadNavesFlotasArribaron();

		/* recorro la lista de flotas que arribaron alguna nave para, enviando
		 * notificacion de arribos para las que correspondan */
		t_idFlotasCantidadCollection::iterator fin = arribaron->end();
		for (t_idFlotasCantidadCollection::iterator it = arribaron->begin();
				it != fin;
				it++)
		{
			cout << "Flota arribo: " << it->first << "(" << it->second << ")" << endl;
			//si arribo la flota o se fuerza la notificacion, se notifica
			if (it->second == 0)
			{			//elimino la informacion de la flota
				it = arribaron->erase(it);
			}
		}

	}
}

int main(int argc, char **argv) {
//	f1 = crearFlota(d1,partida);
//	f2 = crearFlota(d2,partida2);
//
//	cout << "********************* flota 1 **************************\n";
//	imprimirFlota(*f1);
//
//	cout << "\n********************* flota 2 **************************\n";
//	imprimirFlota(*f2);
//
//	ColeccionFlotas cf;
//	cf.add(f1);
//	cf.add(f2);

	//verificarCantidadArribaran(cf);

	//verificarTiempoArribaran(cf);

	//verificarQuedo (cf);

	//verificarCantidadArribaranInf(cf);

	//verificarArribadas(cf);

	//verificarTiempoArribaranSuc(cf);

	verificarArribosSucesivos();
}

